const { spawn } = require('child_process')
const { join } = require('path')
module.exports = class Git {
    constructor(root, repo) {
        // 具体仓库地址
        if (!/\.git$/.test(repo)) {
            repo += '.git'
        }
        this.repoPath = join(root, repo)
    }
    repoIndo() {
        return new Promise(resolve => {
            const child = spawn('git', ['for-each-ref', '--format=%(refname)'], {
                cwd: join(this.repoPath)
            })
            child.stdout.on('data', buffer => {
                const data = buffer.toString('utf-8')
                const array = data.split('\n')
                array.pop()
                resolve(array)
            })
        })
    }
    // 获取所有分支
    branch() {
        return new Promise(resolve => {
            const child = spawn('git', ['for-each-ref', '--format=%(refname)'], {
                cwd: join(this.repoPath)
            })
            child.stdout.on('data', buffer => {
                const data = buffer.toString('utf-8')
                const array = data.split('\n')
                array.pop()
                resolve(array)
            })
        })
    }
    // 获取指定分支的所有log
    log(branchName) {
        return new Promise(resolve => {
            const res = []
            const child = spawn('git', ['log', '--format=%cN{@}%cd{@}%h{@}%t{@}%B', branchName], {
                cwd: join(this.repoPath)
            })
            child.stdout.on('data', buffer => {
                const data = buffer.toString('utf-8')
                const array = data.split('\n')
                array.pop()
                array.forEach(item => {
                    if (item) {
                        const arr = item.split('{@}')
                        res.push( {
                            username: arr[0], // 提交者名称
                            time: arr[1], // 提交时间
                            commitHash: arr[2],
                            treeHash: arr[3],
                            body: arr[4],
                        })
                    }
                })
            })
            // 可能是流的原因，要接收多次data才能获取
            // 到所有log
            child.on('close', () => {
                resolve(res)
            })
        })
    }
    // 获取指定分支最新的log
    lastestTreeByBranch(branchName) {
        return new Promise(resolve => {
            const child = spawn('git', ['cat-file', '-p', branchName], {
                cwd: join(this.repoPath)
            })
            child.stdout.on('data', buffer => {
                const data = buffer.toString('utf-8')
                const array = data.split('\n')
                const keyValue = array[0].split(' ')
                resolve(keyValue[1])
            })
        })
    }
    // 目录
    ls(treeHash) {
        return new Promise(resolve => {
            const child = spawn('git', ['cat-file', '-p', treeHash], {
                cwd: this.repoPath,
            })
            const res = []
            child.stdout.on('data', data => {
                let str = data.toString('utf-8')
                str.split('\n').forEach(item => {
                    if (item) {
                        const array = item.split(' ')
                        const hashOrName = array[2].split('\t')
                        const it = {
                            type: array[1],
                            hash: hashOrName[0],
                            name: hashOrName[1],
                        }
                        res.push(it);
                    }
                })
            })
            child.on('close', () => {
                resolve(res)
            })
        })
    }
    blob(blobHash) {
        return new Promise(resolve => {
            const child = spawn('git', ['cat-file', '-p', blobHash], {
                cwd: this.repoPath
            })
            child.stdout.on('data', buffer => {
                resolve(buffer.toString('utf-8'))
            })
        })
    }
    // 将所有文件的增改信息，放入哈希表中
    commitDiff(commitHash, time, body) {
        return new Promise(resolve => {
            const map = {}
            const child = spawn('git', ['diff-tree', '-r', '--full-index', '--root', commitHash], {
                cwd: this.repoPath
            })
            child.stdout.on('data', buffer => {
                buffer.toString('utf-8').split('\n').forEach(item => {
                    if (item[0] === ':') {
                        const leftFileHash = item.slice(15, 55)
                        const rightFileHash = item.slice(56, 96)
                        const type = item.slice(97, 98)
                        // \t 是一个字符 注意了
                        const dotFilename = item.slice(99, item.length)
                        const goal = {
                            type,
                            dotFilename,
                            time,
                            body,
                        }
                        // 删除文件后，右边的hash是000000000......
                        // 但是，如果使用左边的话，就会冲突，因为一定会存在一次添加/修改
                        // 的hash值和删除时相同。
                        // 所以，我们不保存删除的
                        if (type !== 'D') {
                            goal.hash = rightFileHash
                            map[goal.hash] = goal;
                        }
                    }
                })
            })
            child.on('close', () => {
                resolve(map)
            })
        })
    }
}